// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest

#include "lib/BSMSnapshotModel.hpp"
#include "lib/protocol_related_types.hpp"
#include "lib/sunspec_models.hpp"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <initializer_list>
#include <iostream>
#include <numeric>

// clang-format off
constexpr PointInitializerList init_list = {
    { "acc32" , PointType::acc32 },
    { "bitfield32", PointType::bitfield32 } ,
    { "enum16", PointType::enum16 , 70 }, // just a test, this should be ignored.
    { "int16" , PointType::int16 },
    { "pad" , PointType::pad , 1 },
    { "sunsf" , PointType::uint16 },
    { "uint32", PointType::uint32 },
    { "string", PointType::string , 70 },
    { "dummy" , PointType::acc32 },
};
// clang-format on

constexpr PointArray<init_list.size()> model(calc_offset<init_list.size()>(init_list));

using SunspecModelBaseTest = SunspecModelBase<init_list.size(), init_list>;

TEST(TestTypes, AddressTypes) {

    // test user defined literal stuff.

    protocol_related_types::ModbusRegisterAddress m0{10_mra};
    protocol_related_types::ModbusRegisterAddress m1{10_sma};

    EXPECT_EQ(m0.val, 10);
    EXPECT_EQ(m1.val, 9);

    protocol_related_types::SunspecDataModelAddress s0{10_mra};
    protocol_related_types::SunspecDataModelAddress s1{10_sma};

    EXPECT_EQ(s0.val, 11);
    EXPECT_EQ(s1.val, 10);

    s0 = m0;
    EXPECT_EQ(s0.val, 11);

    m0 = s0;
    EXPECT_EQ(m0.val, 10);

    protocol_related_types::SunspecDataModelAddress sdm_address{10};
    protocol_related_types::ModbusRegisterAddress mr_address{100};

    protocol_related_types::ModbusRegisterAddress mb_result_address{mr_address + sdm_address};
    EXPECT_EQ(mb_result_address.val, 109);

    protocol_related_types::SunspecDataModelAddress sdb_result_address{mr_address + sdm_address};
    EXPECT_EQ(sdb_result_address.val, 110);
}

TEST(TestSnapshotModels, calc_offset) {

    // verify init of offset in models

    EXPECT_EQ(model.size(), init_list.size());
    EXPECT_EQ(model.at(0).offset, 0);   // acc32       2
    EXPECT_EQ(model.at(1).offset, 4);   // bitfield32  2
    EXPECT_EQ(model.at(2).offset, 8);   // enum16      1
    EXPECT_EQ(model.at(3).offset, 10);  // int16      1
    EXPECT_EQ(model.at(4).offset, 12);  // pad        1
    EXPECT_EQ(model.at(5).offset, 14);  // sunsf      1
    EXPECT_EQ(model.at(6).offset, 16);  // uint32     2
    EXPECT_EQ(model.at(7).offset, 20);  // string
    EXPECT_EQ(model.at(8).offset, 160); // dummy
}

TEST(TestSnapshotModels, TestModelLength) {

    // check that calc_model_size_in_bytes works correctly
    static_assert(calc_model_size_in_bytes(model) == 164);
}

TEST(TestSnapshotModels, TestBSMSnapshotModelData) {

    EXPECT_EQ(bsm::SignedSnapshot::Model.size(), bsm::BSMSnapshotPointInitList.size());
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(0).offset, 0);    // e16
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(1).offset, 2);    // e16
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(2).offset, 4);    // acc32
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(3).offset, 8);    // acc32
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(4).offset, 12);   // sunssf
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(5).offset, 14);   // int16
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(6).offset, 16);   // sunssf
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(7).offset, 18);   // string 8
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(8).offset, 34);   // uint32
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(9).offset, 38);   // uint32
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(10).offset, 42);  // uint32
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(11).offset, 46);  // int16
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(12).offset, 48);  // uint32
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(13).offset, 52);  // uint32
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(14).offset, 56);  // uint16
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(15).offset, 58);  // uint16
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(16).offset, 60);  // string 70
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(17).offset, 200); // string 50
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(18).offset, 300); // string 50
    EXPECT_EQ(bsm::SignedSnapshot::Model.at(19).offset, 400); // bitfield32
}

transport::DataVector create_test_data(std::initializer_list<transport::DataVector::value_type> il,
                                       std::size_t result_size) {
    transport::DataVector result(result_size);

    auto it = result.begin();
    for (auto item : il)
        (*it++) = item;

    return result;
}

TEST(TestSunspecModelBase, UnsignedConvsersion) {

    // we fake a vector with the size of a respone DataVector from modbus that is large enough for the model in
    // question.
    transport::DataVector data{create_test_data({0xff, 0xee, 0xdd, 0xcc, 0x00}, calc_model_size_in_bytes(model))};

    std::uint32_t val32{0xffeeddcc};
    SunspecModelBaseTest smb(data);
    EXPECT_EQ(smb.uint32_at(0), val32);

    std::uint16_t val16{0xeedd};
    EXPECT_EQ(smb.uint16_at(1), val16);
}

TEST(TestSunspecModelBase, SignedConvsersion) {

    {
        transport::DataVector signed_data{create_test_data({0xfb, 0x2e}, calc_model_size_in_bytes(model))}; // -1234
        SunspecModelBaseTest smb(signed_data);

        std::int16_t result{-1234};

        EXPECT_EQ(smb.int16_at(0), result);
    }

    {
        transport::DataVector signed_data{create_test_data({0x80, 0x00}, calc_model_size_in_bytes(model))};
        SunspecModelBaseTest smb(signed_data);

        std::int16_t result{std::numeric_limits<std::int16_t>::min()};

        EXPECT_EQ(smb.int16_at(0), result);
    }

    {
        transport::DataVector signed_data{create_test_data({0x7f, 0xff}, calc_model_size_in_bytes(model))};
        SunspecModelBaseTest smb(signed_data);

        std::int16_t result{std::numeric_limits<std::int16_t>::max()};

        EXPECT_EQ(smb.int16_at(0), result);
    }

    {
        transport::DataVector signed_data{create_test_data({0x00, 0x00}, calc_model_size_in_bytes(model))};
        SunspecModelBaseTest smb(signed_data);

        std::int16_t result{0};

        EXPECT_EQ(smb.int16_at(0), result);
    }
}

TEST(TestSunspecModelBase, StringConversion) {

    transport::DataVector string_data{
        create_test_data({'H', 'e', 'r', 'b', 'e', 'r', 't'}, calc_model_size_in_bytes(model))};
    std::string result{"Herbert"};
    SunspecModelBaseTest smb(string_data);
    EXPECT_EQ(smb.string_at_with_length(0, 7), result);
}

TEST(TestSunspecModelBaseTest, EmptyContainer) {

    transport::DataVector empty;

    ASSERT_THROW(sunspec_model::Common sc(empty), std::runtime_error);
}

// clang-format off
/*
 * snapshot status regiser is 40524 => 9E4C
 *
>bsmtool --verbose --trace --device /dev/ttyUSB0 get-snapshot signed_current_snapshot
/dev/ttyUSB0:42[addr=40524] ->2A109E4C0001020002BCA5 ==> write update into register
/dev/ttyUSB0:42[addr=40524] <--2A109E4C0001E9ED      ==> return snapshot is valid
/dev/ttyUSB0:42[addr=40523] ->2A039E4B00641DC4       ==> read data
/dev/ttyUSB0:42[addr=40523] <--2A 03 C800 0000 0000 0015 AE00 001BB2000000000001303031425A5231353231303730303139000001640016EFAAFFFFFFFF8000000000390016A42C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F3E2
/dev/ttyUSB0:42[addr=40623] ->2A039EAF007D9C39      ==> continue read data
/dev/ttyUSB0:42[addr=40623] <--2A03FA000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000473045022040917A89270AD73DBFCFAF187C592DF0962E2BABBCC1C6A8D4456B5DB5E76BD6022100E1652CD40D
/dev/ttyUSB0:42[addr=40748] ->2A039F2C001BEC07      ==> continue read data
/dev/ttyUSB0:42[addr=40748] <--2A03360A6CDB7F9C732654DA09286730C16FE9EC853687523CBFF459F87AA9030000000000000000000000000000000000000000000000000057B6
Updating 'signed_current_snapshot' succeeded
Snapshot data:
bsm_snapshot:
    ID: 64901
    L: 252
    fixed:
        Typ: 0
        St: 0
        RCR: 5550 Wh
        TotWhImp: 7090 Wh
        W: 0.0 W
        MA1: 001BZR1521070019
        RCnt: 356
        OS: 1503146 s
        Epoch: None
        TZO: None
        EpochSetCnt: 57
        EpochSetOS: 1483820 s
        DI: 0
        DO: 0
        Meta1: None
        Meta2: None
        Meta3: None
        Evt: 0
        NSig: 48
        BSig: 71
    repeating blocks blob:
        Sig: 3045022040917a89270ad73dbfcfaf187c592df0962e2babbcc1c6a8d4456b5db5e76bd6022100e1652c0a6cdb7f9c732654da09286730c16fe9ec853687523cbff459f87aa903

 */
// clang-format on

TEST(TestModel, BSMSignedSnapshot) {

    // device id, function code, number of bytes ... crc crc

    transport::DataVector data = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xAE, 0x00, 0x00, 0x1B, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0x30, 0x30, 0x31, 0x42, 0x5A, 0x52, 0x31, 0x35, 0x32, 0x31, 0x30, 0x37, 0x30, 0x30, 0x31, 0x39, 0x00, 0x00,
        0x01, 0x64, 0x00, 0x16, 0xEF, 0xAA, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x16,
        0xA4, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20, 0x40, 0x91,
        0x7A, 0x89, 0x27, 0x0A, 0xD7, 0x3D, 0xBF, 0xCF, 0xAF, 0x18, 0x7C, 0x59, 0x2D, 0xF0, 0x96, 0x2E, 0x2B, 0xAB,
        0xBC, 0xC1, 0xC6, 0xA8, 0xD4, 0x45, 0x6B, 0x5D, 0xB5, 0xE7, 0x6B, 0xD6, 0x02, 0x21, 0x00, 0xE1, 0x65, 0x2C,
        0x0A, 0x6C, 0xDB, 0x7F, 0x9C, 0x73, 0x26, 0x54, 0xDA, 0x09, 0x28, 0x67, 0x30, 0xC1, 0x6F, 0xE9, 0xEC, 0x85,
        0x36, 0x87, 0x52, 0x3C, 0xBF, 0xF4, 0x59, 0xF8, 0x7A, 0xA9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    bsm::SignedSnapshot signed_snapshot(data);

    EXPECT_EQ(signed_snapshot.Type(), 0);

    EXPECT_EQ(signed_snapshot.Status(), 0);

    EXPECT_EQ(signed_snapshot.RCR(), 5550);

    EXPECT_EQ(signed_snapshot.TotWhImp(), 7090);

    EXPECT_EQ(signed_snapshot.W(), 0);

    EXPECT_EQ(signed_snapshot.MA1(), "001BZR1521070019");

    EXPECT_EQ(signed_snapshot.RCnt(), 356);

    EXPECT_EQ(signed_snapshot.OS(), 1503146);

    EXPECT_EQ(signed_snapshot.Epoch(), invalid_point_value::uint32);

    EXPECT_EQ(signed_snapshot.TZO(), invalid_point_value::int16);

    EXPECT_EQ(signed_snapshot.EpochSetCnt(), 57);

    EXPECT_EQ(signed_snapshot.EpochSetOS(), 1483820);

    EXPECT_EQ(signed_snapshot.DI(), 0);

    EXPECT_EQ(signed_snapshot.DO(), 0);

    EXPECT_FALSE(invalid_point_value::valid_string(signed_snapshot.Meta1()));

    EXPECT_FALSE(invalid_point_value::valid_string(signed_snapshot.Meta2()));

    EXPECT_FALSE(invalid_point_value::valid_string(signed_snapshot.Meta3()));

    EXPECT_EQ(signed_snapshot.Evt(), 0);

    EXPECT_EQ(signed_snapshot.NSig(), 48);

    EXPECT_EQ(signed_snapshot.BSig(), 71);

    {
        std::string expected{"3045022040917a89270ad73dbfcfaf187c592df0962e2babbcc1c6a8d4456b5db5e76bd6022100e1652c0a6cd"
                             "b7f9c732654da09286730c16fe9ec853687523cbff459f87aa903"};
        std::string converted{signed_snapshot.Sig()};
        EXPECT_EQ(expected, converted);
    }

    {
        std::string expected{
            "3045022040917a89270ad73dbfcfaf187c592df0962e2babbcc1c6a8d4456b5db5e76bd6022100e1652c0a6cdb7f9c732654da0928"
            "6730c16fe9ec853687523cbff459f87aa90300000000000000000000000000000000000000000000000000"};
        std::string converted{signed_snapshot.SigPadded()};
        EXPECT_EQ(expected, converted);
    }

    // model_to_stream(std::cout, signed_snapshot, { 5, // watt
    //                                               8, // response counter
    //                                               9, // Operation seconds
    //     } );
}

TEST(TestModel, BSMOCMFSignedSnapshot) {

    // clang-format off
/*
>bsmtool --trace --verbose --device /dev/ttyUSB0 get oscs
/dev/ttyUSB0:42[addr=41793] ->2A03A3410002B040
/dev/ttyUSB0:42[addr=41793] <--2A0304000000006131
/dev/ttyUSB0:42[addr=41795] ->2A03a343007D5060 ==> Start reading at modbus address 41795, sunspec address 41795
/dev/ttyUSB0:42[addr=41795] <--2A0316#16FA4F434D467C7B224656223A22312E30222C224749223A22424155455220456C656374726F6E69632042534D2D57533336412D4830312D313331312D30303030222C224753223A22303031425A5231353231303730303139222C224756223A22312E393A333243413A414646342C2036643164643363222C225047223A2254353635222C224D56223A22424155455220456C656374726F6E6963222C224D4D223A2242534D2D57533336412D4830312D313331312D30303030222C224D53223A22303031425A5231353231303730303139222C224953223A66616C73652C224954223A22554E444546494E4544222C224944223A22222C22524422396A
/dev/ttyUSB0:42[addr=41920] ->2A03A3C0007DA188
/dev/ttyUSB0:42[addr=41920] <--2A03FA3A5B7B22544D223A22313937302D30312D30315430303A30303A30302C3030302B303030302055222C225458223A2243222C225256223A313934302C225249223A22312D303A312E382E302A313938222C225255223A225768222C225856223A393034302C225849223A22312D303A312E382E302A323535222C225855223A225768222C225854223A302C225254223A224143222C224546223A22222C225354223A2247227D5D7D7C7B225341223A2245434453412D7365637032353672312D534841323536222C225344223A2233303434303232303236653162333033333364353762313537633339353934343964643766623536323630365ED7
/dev/ttyUSB0:42[addr=42045] ->2A03A43D007D310C
/dev/ttyUSB0:42[addr=42045] <--2A03FA623436393232643463373834663862366165316664313333633566363032323036303666623735306133653864363334303932333737333365623762623464353634653238633731343633303531343362643832383561666331623330643165227D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009EFF
/dev/ttyUSB0:42[addr=42170] ->2A03A4BA007980E6
/dev/ttyUSB0:42[addr=42170] <--2A03F20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000443C



bsm_ocmf:
    ID: 64903
    L: 498
    Typ: 0
    St: 0
    O: OCMF|{"FV":"1.0","GI":"BAUER Electronic BSM-WS36A-H01-1311-0000","GS":"001BZR1521070019","GV":"1.9:32CA:AFF4, 6d1dd3c","PG":"T565","MV":"BAUER Electronic","MM":"BSM-WS36A-H01-1311-0000","MS":"001BZR1521070019","IS":false,"IT":"UNDEFINED","ID":"","RD":[{"TM":"1970-01-01T00:00:00,000+0000 U","TX":"C","RV":1940,"RI":"1-0:1.8.0*198","RU":"Wh","XV":9040,"XI":"1-0:1.8.0*255","XU":"Wh","XT":0,"RT":"AC","EF":"","ST":"G"}]}|{"SA":"ECDSA-secp256r1-SHA256","SD":"3044022026e1b30333d57b157c3959449dd7fb562606b46922d4c784f8b6ae1fd133c5f60220606fb750a3e8d63409237733eb7bb4d564e28c7146305143bd8285afc1b30d1e"}

     */

    // clang-format on

    transport::DataVector data = {
        0xFD, 0x87, // added sunspec model number

        0x01, 0x74, // default payload length

        0x00, 0x00, // snapshot type

        0x00, 0x00, // status

        0x4F, 0x43, 0x4D, 0x46, 0x7C, 0x7B, 0x22, 0x46, 0x56, 0x22, 0x3A, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x2C, 0x22,
        0x47, 0x49, 0x22, 0x3A, 0x22, 0x42, 0x41, 0x55, 0x45, 0x52, 0x20, 0x45, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F,
        0x6E, 0x69, 0x63, 0x20, 0x42, 0x53, 0x4D, 0x2D, 0x57, 0x53, 0x33, 0x36, 0x41, 0x2D, 0x48, 0x30, 0x31, 0x2D,
        0x31, 0x33, 0x31, 0x31, 0x2D, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2C, 0x22, 0x47, 0x53, 0x22, 0x3A, 0x22, 0x30,
        0x30, 0x31, 0x42, 0x5A, 0x52, 0x31, 0x35, 0x32, 0x31, 0x30, 0x37, 0x30, 0x30, 0x31, 0x39, 0x22, 0x2C, 0x22,
        0x47, 0x56, 0x22, 0x3A, 0x22, 0x31, 0x2E, 0x39, 0x3A, 0x33, 0x32, 0x43, 0x41, 0x3A, 0x41, 0x46, 0x46, 0x34,
        0x2C, 0x20, 0x36, 0x64, 0x31, 0x64, 0x64, 0x33, 0x63, 0x22, 0x2C, 0x22, 0x50, 0x47, 0x22, 0x3A, 0x22, 0x54,
        0x35, 0x36, 0x35, 0x22, 0x2C, 0x22, 0x4D, 0x56, 0x22, 0x3A, 0x22, 0x42, 0x41, 0x55, 0x45, 0x52, 0x20, 0x45,
        0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x22, 0x2C, 0x22, 0x4D, 0x4D, 0x22, 0x3A, 0x22, 0x42,
        0x53, 0x4D, 0x2D, 0x57, 0x53, 0x33, 0x36, 0x41, 0x2D, 0x48, 0x30, 0x31, 0x2D, 0x31, 0x33, 0x31, 0x31, 0x2D,
        0x30, 0x30, 0x30, 0x30, 0x22, 0x2C, 0x22, 0x4D, 0x53, 0x22, 0x3A, 0x22, 0x30, 0x30, 0x31, 0x42, 0x5A, 0x52,
        0x31, 0x35, 0x32, 0x31, 0x30, 0x37, 0x30, 0x30, 0x31, 0x39, 0x22, 0x2C, 0x22, 0x49, 0x53, 0x22, 0x3A, 0x66,
        0x61, 0x6C, 0x73, 0x65, 0x2C, 0x22, 0x49, 0x54, 0x22, 0x3A, 0x22, 0x55, 0x4E, 0x44, 0x45, 0x46, 0x49, 0x4E,
        0x45, 0x44, 0x22, 0x2C, 0x22, 0x49, 0x44, 0x22, 0x3A, 0x22, 0x22, 0x2C, 0x22, 0x52, 0x44, 0x22, 0x3A, 0x5B,
        0x7B, 0x22, 0x54, 0x4D, 0x22, 0x3A, 0x22, 0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31, 0x54,
        0x30, 0x30, 0x3A, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x2C, 0x30, 0x30, 0x30, 0x2B, 0x30, 0x30, 0x30, 0x30, 0x20,
        0x55, 0x22, 0x2C, 0x22, 0x54, 0x58, 0x22, 0x3A, 0x22, 0x43, 0x22, 0x2C, 0x22, 0x52, 0x56, 0x22, 0x3A, 0x31,
        0x39, 0x34, 0x30, 0x2C, 0x22, 0x52, 0x49, 0x22, 0x3A, 0x22, 0x31, 0x2D, 0x30, 0x3A, 0x31, 0x2E, 0x38, 0x2E,
        0x30, 0x2A, 0x31, 0x39, 0x38, 0x22, 0x2C, 0x22, 0x52, 0x55, 0x22, 0x3A, 0x22, 0x57, 0x68, 0x22, 0x2C, 0x22,
        0x58, 0x56, 0x22, 0x3A, 0x39, 0x30, 0x34, 0x30, 0x2C, 0x22, 0x58, 0x49, 0x22, 0x3A, 0x22, 0x31, 0x2D, 0x30,
        0x3A, 0x31, 0x2E, 0x38, 0x2E, 0x30, 0x2A, 0x32, 0x35, 0x35, 0x22, 0x2C, 0x22, 0x58, 0x55, 0x22, 0x3A, 0x22,
        0x57, 0x68, 0x22, 0x2C, 0x22, 0x58, 0x54, 0x22, 0x3A, 0x30, 0x2C, 0x22, 0x52, 0x54, 0x22, 0x3A, 0x22, 0x41,
        0x43, 0x22, 0x2C, 0x22, 0x45, 0x46, 0x22, 0x3A, 0x22, 0x22, 0x2C, 0x22, 0x53, 0x54, 0x22, 0x3A, 0x22, 0x47,
        0x22, 0x7D, 0x5D, 0x7D, 0x7C, 0x7B, 0x22, 0x53, 0x41, 0x22, 0x3A, 0x22, 0x45, 0x43, 0x44, 0x53, 0x41, 0x2D,
        0x73, 0x65, 0x63, 0x70, 0x32, 0x35, 0x36, 0x72, 0x31, 0x2D, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x22, 0x2C,
        0x22, 0x53, 0x44, 0x22, 0x3A, 0x22, 0x33, 0x30, 0x34, 0x34, 0x30, 0x32, 0x32, 0x30, 0x32, 0x36, 0x65, 0x31,
        0x62, 0x33, 0x30, 0x33, 0x33, 0x33, 0x64, 0x35, 0x37, 0x62, 0x31, 0x35, 0x37, 0x63, 0x33, 0x39, 0x35, 0x39,
        0x34, 0x34, 0x39, 0x64, 0x64, 0x37, 0x66, 0x62, 0x35, 0x36, 0x32, 0x36, 0x30, 0x36, 0x62, 0x34, 0x36, 0x39,
        0x32, 0x32, 0x64, 0x34, 0x63, 0x37, 0x38, 0x34, 0x66, 0x38, 0x62, 0x36, 0x61, 0x65, 0x31, 0x66, 0x64, 0x31,
        0x33, 0x33, 0x63, 0x35, 0x66, 0x36, 0x30, 0x32, 0x32, 0x30, 0x36, 0x30, 0x36, 0x66, 0x62, 0x37, 0x35, 0x30,
        0x61, 0x33, 0x65, 0x38, 0x64, 0x36, 0x33, 0x34, 0x30, 0x39, 0x32, 0x33, 0x37, 0x37, 0x33, 0x33, 0x65, 0x62,
        0x37, 0x62, 0x62, 0x34, 0x64, 0x35, 0x36, 0x34, 0x65, 0x32, 0x38, 0x63, 0x37, 0x31, 0x34, 0x36, 0x33, 0x30,
        0x35, 0x31, 0x34, 0x33, 0x62, 0x64, 0x38, 0x32, 0x38, 0x35, 0x61, 0x66, 0x63, 0x31, 0x62, 0x33, 0x30, 0x64,
        0x31, 0x65, 0x22, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00};

    bsm::SignedOCMFSnapshot signedOCMFSnapshot(data);

    // model_to_stream(std::cout, signedOCMFSnapshot, { 0 ,1,2,3, 4 } );

    std::string expected_ocmf_string{
        "OCMF|{\"FV\":\"1.0\",\"GI\":\"BAUER Electronic "
        "BSM-WS36A-H01-1311-0000\",\"GS\":\"001BZR1521070019\",\"GV\":\"1.9:32CA:AFF4, "
        "6d1dd3c\",\"PG\":\"T565\",\"MV\":\"BAUER "
        "Electronic\",\"MM\":\"BSM-WS36A-H01-1311-0000\",\"MS\":\"001BZR1521070019\",\"IS\":false,\"IT\":\"UNDEFINED\","
        "\"ID\":\"\",\"RD\":[{\"TM\":\"1970-01-01T00:00:00,000+0000 "
        "U\",\"TX\":\"C\",\"RV\":1940,\"RI\":\"1-0:1.8.0*198\",\"RU\":\"Wh\",\"XV\":9040,\"XI\":\"1-0:1.8.0*255\","
        "\"XU\":\"Wh\",\"XT\":0,\"RT\":\"AC\",\"EF\":\"\",\"ST\":\"G\"}]}|{\"SA\":\"ECDSA-secp256r1-SHA256\",\"SD\":"
        "\"3044022026e1b30333d57b157c3959449dd7fb562606b46922d4c784f8b6ae1fd133c5f60220606fb750a3e8d63409237733eb7bb4d5"
        "64e28c7146305143bd8285afc1b30d1e\"}"};

    // This should be enough testing here...
    EXPECT_EQ(signedOCMFSnapshot.O(), expected_ocmf_string);
}

TEST(TestModel, SunspecACMeter) {

    // clang-format off
    /*

>bsmtool --trace --verbose --device /dev/ttyUSB0 get ac_meter

/dev/ttyUSB0:42[addr=40092] ->2A039C9C00696D81 9c9c: 40092 => Sunspec Address 40093, this means the BSM python tool skips ModelID (40091) and Model payload length (40092)
/dev/ttyUSB0:42[addr=40092] <--2A03D2000D000D00000000FFFE8000093C000000008000800080008000FFFF01F4FFFF0002000200000000000100030003000000000001FFFEFFFE000000000001800002AE00000000FFFF00000000000000000000000000000000000022A60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000092F5
ac_meter:
    ID: 203
    L: 105
    A: 0.13 A
    AphA: 0.13 A
    AphB: 0.0 A
    AphC: 0.0 A
    PhV: None
    PhVphA: 236.4 V
    PhVphB: 0.0 V
    PhVphC: 0.0 V
    PPV: None
    PhVphAB: None
    PhVphBC: None
    PhVphCA: None
    Hz: 50.0 Hz
    W: 20.0 W
    WphA: 20.0 W
    WphB: 0.0 W
    WphC: 0.0 W
    VA: 30.0 VA
    VAphA: 30.0 VA
    VAphB: 0.0 VA
    VAphC: 0.0 VA
    VAR: -20.0 var
    VARphA: -20.0 var
    VARphB: 0.0 var
    VARphC: 0.0 var
    PF: None
    PFphA: 68.60000000000001 Pct
    PFphB: 0.0 Pct
    PFphC: 0.0 Pct
    TotWhExp: None
    TotWhExpPhA: None
    TotWhExpPhB: None
    TotWhExpPhC: None
    TotWhImp: 8870 Wh
    TotWhImpPhA: None
    TotWhImpPhB: None
    TotWhImpPhC: None
    TotVAhExp: None
    TotVAhExpPhA: None
    TotVAhExpPhB: None
    TotVAhExpPhC: None
    TotVAhImp: None
    TotVAhImpPhA: None
    TotVAhImpPhB: None
    TotVAhImpPhC: None
    TotVArhImpQ1: None
    TotVArhImpQ1PhA: None
    TotVArhImpQ1PhB: None
    TotVArhImpQ1PhC: None
    TotVArhImpQ2: None
    TotVArhImpQ2PhA: None
    TotVArhImpQ2PhB: None
    TotVArhImpQ2PhC: None
    TotVArhExpQ3: None
    TotVArhExpQ3PhA: None
    TotVArhExpQ3PhB: None
    TotVArhExpQ3PhC: None
    TotVArhExpQ4: None
    TotVArhExpQ4PhA: None
    TotVArhExpQ4PhB: None
    TotVArhExpQ4PhC: None
    Evt: 0


    The original data obtained from the powermeter have been changed, since the bsm python tool starts reading at sunspec address 40093,
    but SunspecModel::ACMeter expects the data to start at sunspec address 40091.
    The first four bytes have been added manually and are the default values for this sunspec model.
    */

    // clang-format on

    transport::DataVector data = {0x00, 203,  0x00, 105,  0x00, 0x0D, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
                                  0x80, 0x00, 0x09, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
                                  0x80, 0x00, 0xFF, 0xFF, 0x01, 0xF4, 0xFF, 0xFF, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
                                  0xFF, 0xFE, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x02, 0xAE,
                                  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xA6, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
                                  0x00, 0x00, 0x00, 0x00}; // , 0x92, 0xF5 };

    sunspec_model::ACMeter ac_meter(data);

    std::cout << "ID : " << ac_meter.ID() << std::endl;
    std::cout << "A  : " << ac_meter.A() << std::endl;

    // model_to_stream(std::cout, ac_meter, { 0, 1 ,2 ,3 , 4 ,5 , 6 , 8 , 36 } );

    EXPECT_FLOAT_EQ(ac_meter.A() * pow(10, ac_meter.A_SF()), 0.13);        // check Amps and its scaling factor

    EXPECT_FLOAT_EQ(ac_meter.PhVphA() * pow(10, ac_meter.PF_SF()), 236.4); // check PhVphA and scaling factor

    EXPECT_FLOAT_EQ(ac_meter.Hz() * pow(10, ac_meter.Hz_SF()), 50.0);      // check Hz and scaling factor

    // same stuff for the other suspects.

    EXPECT_FLOAT_EQ(ac_meter.W() * pow(10, ac_meter.W_SF()), 20.0);

    EXPECT_FLOAT_EQ(ac_meter.VA() * pow(10, ac_meter.VA_SF()), 30.0);

    EXPECT_FLOAT_EQ(ac_meter.VAphA() * pow(10, ac_meter.VA_SF()), 30.0);

    EXPECT_FLOAT_EQ(ac_meter.VAR() * pow(10, ac_meter.VAR_SF()), -20.0);

    EXPECT_FLOAT_EQ(ac_meter.VARphA() * pow(10, ac_meter.VAR_SF()), -20.0);

    EXPECT_FLOAT_EQ(ac_meter.PFphA() * pow(10, ac_meter.PF_SF()), 68.60000000000001);
}

template <typename MODEL>
std::ostream& test_model_to_stream(std::ostream& out, const MODEL& model,
                                   std::initializer_list<std::size_t> index_list) {

    for (std::size_t model_index : index_list) {
        out << "Id : " << MODEL::Model[model_index].id << " offset " << MODEL::Model[model_index].offset << " "
            << " value " << point_value_to_string(model.m_data, MODEL::Model[model_index]) << "\n";
    }

    return out;
}

template <PointType PT, typename T> bool invalid_value(T v) {

    if constexpr (PT == PointType::acc32) {
        return invalid_point_value::acc32 == v;
    }

    if constexpr (PT == PointType::bitfield32) {
        return invalid_point_value::bitfield32 == v;
    }

    if constexpr (PT == PointType::enum16) {
        return invalid_point_value::enum16 == v;
    }

    if constexpr (PT == PointType::int16) {
        return invalid_point_value::int16 == v;
    }

    if constexpr (PT == PointType::sunssf) {
        return invalid_point_value::sunssf == v;
    }

    if constexpr (PT == PointType::uint16) {
        return invalid_point_value::uint16 == v;
    }

    if constexpr (PT == PointType::uint32) {
        return invalid_point_value::uint32 == v;
    }
}

TEST(TestInvalidValues, ValueCheck) {

    transport::DataVector data = {0x00, 203,  0x00, 105,  0x00, 0x0D, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
                                  0x80, 0x00, 0x09, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
                                  0x80, 0x00, 0xFF, 0xFF, 0x01, 0xF4, 0xFF, 0xFF, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
                                  0xFF, 0xFE, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x02, 0xAE,
                                  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xA6, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
                                  0x00, 0x00, 0x00, 0x00}; // , 0x92, 0xF5 };

    sunspec_model::ACMeter ac_meter(data);

    test_model_to_stream(std::cout, ac_meter, {9});

    std::cout << "is invalid: " << std::boolalpha << invalid_value<PointType::acc32>(1) << std::endl;

    std::cout << "is invalid: " << std::boolalpha << invalid_value<PointType::acc32>(invalid_point_value::acc32)
              << std::endl;
}
